package com.och.mrcp.server;

import com.och.mrcp.config.NettyConfig;
import com.och.mrcp.config.SipConfig;
import com.och.mrcp.handler.SipTcpHandler;
import com.och.mrcp.handler.SipUdpHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;

@Slf4j
@Component
@RequiredArgsConstructor
public class SipServer {
    
    private final NettyConfig nettyConfig;
    private final SipConfig sipConfig;
    private final SipUdpHandler sipUdpHandler;
    private final SipTcpHandler sipTcpHandler;
    
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    private Channel tcpChannel;
    private Channel udpChannel;
    private boolean isRunning = false;
    
    @PostConstruct
    public void start() {
        try {
            log.info("Starting SIP server on {}:{} (TCP: {}, UDP: {})", 
                    sipConfig.getLocalIp(), sipConfig.getLocalPort(),
                    sipConfig.isEnableTcp(), sipConfig.isEnableUdp());
            
            bossGroup = new NioEventLoopGroup(nettyConfig.getBossThreads());
            workerGroup = new NioEventLoopGroup(nettyConfig.getWorkerThreads());
            
            // 启动TCP服务器
            if (sipConfig.isEnableTcp()) {
                startTcpServer();
            }
            
            // 启动UDP服务器
            if (sipConfig.isEnableUdp()) {
                startUdpServer();
            }
            
            isRunning = true;
            log.info("SIP server started successfully");
            
        } catch (Exception e) {
            log.error("Failed to start SIP server: {}", e.getMessage(), e);
            throw new RuntimeException("SIP server startup failed", e);
        }
    }
    
    private void startTcpServer() throws InterruptedException {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, sipConfig.getTcpBacklog())
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childOption(ChannelOption.TCP_NODELAY, true)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(sipTcpHandler);
                    }
                });
        
        // 异步绑定，避免阻塞主线程
        bootstrap.bind(sipConfig.getTcpPort()).addListener(future -> {
            if (future.isSuccess()) {
                tcpChannel = ((io.netty.channel.ChannelFuture) future).channel();
                log.info("TCP SIP server started on port {}", sipConfig.getTcpPort());
            } else {
                log.error("Failed to bind TCP SIP server on port {}: {}", 
                        sipConfig.getTcpPort(), future.cause().getMessage());
            }
        });
    }
    
    private void startUdpServer() throws InterruptedException {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(workerGroup)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .handler(sipUdpHandler);
        
        // 异步绑定，避免阻塞主线程
        bootstrap.bind(sipConfig.getUdpPort()).addListener(future -> {
            if (future.isSuccess()) {
                udpChannel = ((io.netty.channel.ChannelFuture) future).channel();
                log.info("UDP SIP server started on port {}", sipConfig.getUdpPort());
            } else {
                log.error("Failed to bind UDP SIP server on port {}: {}", 
                        sipConfig.getUdpPort(), future.cause().getMessage());
            }
        });
    }
    
    @PreDestroy
    public void stop() {
        try {
            log.info("Stopping SIP server...");
            
            if (tcpChannel != null) {
                tcpChannel.close().sync();
            }
            
            if (udpChannel != null) {
                udpChannel.close().sync();
            }
            
            if (bossGroup != null) {
                bossGroup.shutdownGracefully().sync();
            }
            
            if (workerGroup != null) {
                workerGroup.shutdownGracefully().sync();
            }
            
            isRunning = false;
            log.info("SIP server stopped successfully");
            
        } catch (Exception e) {
            log.error("Error stopping SIP server: {}", e.getMessage(), e);
        }
    }
    
    public boolean isRunning() {
        return isRunning;
    }
    
    public int getTcpPort() {
        return sipConfig.getTcpPort();
    }
    
    public int getUdpPort() {
        return sipConfig.getUdpPort();
    }
    
    public String getLocalIp() {
        return sipConfig.getLocalIp();
    }
    
    public boolean isTcpEnabled() {
        return sipConfig.isEnableTcp();
    }
    
    public boolean isUdpEnabled() {
        return sipConfig.isEnableUdp();
    }
}
